use serde::{Deserialize, Serialize};
use serde_json::json;
use crate::commands::user_settings::get_user_settings;
use std::path::{Path, PathBuf};
use std::fs;
use umya_spreadsheet::{reader::xlsx, writer::xlsx as writer};
use dirs;

// 嵌入模板文件
const TEMPLATE_XLSX: &[u8] = include_bytes!("../../template.xlsx");

#[tauri::command]
pub async fn open_folder(folder_path: String) -> Result<(), String> {
    
    println!("=== OPEN_FOLDER 函数被调用 ===");
    println!("🔍 open_folder 接收到的路径: {}", folder_path);
    
    let path = Path::new(&folder_path);
    
    // 检查路径是否存在
    if !path.exists() {
        println!("❌ 路径不存在: {}", folder_path);
        return Err(format!("路径不存在: {}", folder_path));
    }
    
    // 检查是文件还是目录
    if path.is_file() {
        println!("📄 检测到文件路径，将显示该文件: {}", folder_path);
        // 对于文件，使用reveal_item_in_dir来显示文件
        match tauri_plugin_opener::reveal_item_in_dir(&folder_path) {
            Ok(_) => {
                println!("✅ 成功显示文件: {}", folder_path);
                Ok(())
            }
            Err(e) => {
                println!("❌ 显示文件失败: {}", e);
                Err(format!("无法打开文件夹: {}", e))
            }
        }
    } else if path.is_dir() {
        println!("📁 检测到目录路径，将直接打开该目录: {}", folder_path);
        // 对于目录，使用open来直接打开目录
        match tauri_plugin_opener::open_path(&folder_path, None::<String>) {
            Ok(_) => {
                println!("✅ 成功打开目录: {}", folder_path);
                Ok(())
            }
            Err(e) => {
                println!("❌ 打开目录失败: {}", e);
                Err(format!("无法打开文件夹: {}", e))
            }
        }
    } else {
        println!("❓ 未知路径类型: {}", folder_path);
        Err(format!("未知路径类型: {}", folder_path))
    }
}

#[derive(Serialize, Deserialize)]
pub struct GenerateFunctionPointsRequest {
    pub requirement_description: String,
    pub function_point_count: u32,
    pub selected_model: String,
}

#[derive(Serialize, Deserialize)]
pub struct GenerateFunctionPointsResponse {
    pub function_points: Vec<String>,
    pub success: bool,
    pub message: String,
}

#[tauri::command]
pub async fn generate_function_points(
    requirement_description: String,
    function_point_count: u32,
    selected_model: String,
) -> Result<GenerateFunctionPointsResponse, String> {
    // 获取用户设置中的API key
    let user_settings = get_user_settings();
    let api_key = &user_settings.ai_settings.api_key;

    if api_key.is_empty() {
        return Err("请先在设置中配置AI API Key".to_string());
    }

    // API配置
    let base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions";
    let model = &selected_model;

    // 构建prompt
    let prompt = format!(
 r#"
角色设定：
你是一名专业的软件需求分析师，熟悉 COSMIC 功能点方法。你的任务是将业务需求描述转化为明确的功能点（功能性需求单元），用于工作量评估。
输入：
需求描述：{}
期望功能点数量：{}
输出要求：
1. 严格生成 {} 个功能点，数量必须符合要求。
2. 功能点必须是 **核心业务功能**，可实现、可验证。
3. 忽略日志、监控、告警、埋点、调试信息等内容，这些不算功能点。
4. 禁止输出任何括号说明（如"（新增/修改）""（仅阅知）"等），只保留功能点名称。
5. 输出格式统一为：
功能点清单（共 {} 个）：
1. 【功能点1】
2. 【功能点2】
..."#,
        requirement_description,
        function_point_count,
        function_point_count,
        function_point_count
    );

    // 构造请求体
    let body = json!({
        "model": model,
        "messages": [
            { "role": "system", "content": "You are a helpful assistant." },
            { "role": "user", "content": prompt }
        ]
    });

    // 创建HTTP客户端并发送请求
    let client = reqwest::Client::new();
    let response = client
        .post(base_url)
        .header("Authorization", format!("Bearer {}", api_key))
        .header("Content-Type", "application/json")
        .json(&body)
        .send()
        .await
        .map_err(|e| format!("请求错误: {}", e))?;

    // 检查响应状态
    if !response.status().is_success() {
        let status = response.status();
        let text = response.text().await.unwrap_or_default();
        return Err(format!("请求失败，状态码 {}: {}", status, text));
    }

    // 解析响应
    let response_json: serde_json::Value = response
        .json()
        .await
        .map_err(|e| format!("解析响应失败: {}", e))?;

    // 提取AI回复内容
    let content = response_json
        .get("choices")
        .and_then(|choices| choices.get(0))
        .and_then(|choice| choice.get("message"))
        .and_then(|message| message.get("content"))
        .and_then(|content| content.as_str())
        .ok_or("无法获取AI回复内容")?;

    // 解析功能点列表（简单按行分割）
    let function_points: Vec<String> = content
        .lines()
        .map(|line| line.trim())
        .filter(|line| !line.is_empty() && !line.starts_with("#"))
        .map(|line| {
            // 移除可能的序号前缀
            if let Some(pos) = line.find("、") {
                line[pos + 3..].trim().to_string()
            } else if let Some(pos) = line.find(".") {
                line[pos + 1..].trim().to_string()
            } else {
                line.to_string()
            }
        })
        .collect();

    Ok(GenerateFunctionPointsResponse {
        function_points,
        success: true,
        message: "功能点生成成功".to_string(),
    })
}

#[derive(Serialize, Deserialize)]
pub struct GenerateCosmicRequest {
    pub requirement_name: String,
    pub requirement_description: String,
    pub function_points: Vec<String>,
    pub data_movement_groups: u32,
    pub selected_model: String,
}

#[derive(Serialize, Deserialize)]
pub struct GenerateCosmicResponse {
    pub file_path: Option<String>,
    pub success: bool,
    pub message: String,
}

#[tauri::command]
pub async fn generate_cosmic_content(
    requirement_name: String,
    requirement_description: String,
    function_points: Vec<String>,
    data_movement_groups: u32,
    selected_model: String,
) -> Result<GenerateCosmicResponse, String> {
    println!("🚀 开始生成COSMIC内容 - 多线程分组处理模式");
    println!("📝 需求名称: {}", requirement_name);
    println!("📋 功能点数量: {}", function_points.len());
    println!("🔢 数据移动组数: {}", data_movement_groups);
    println!("🤖 选择的模型: {}", selected_model);
    
    // 获取用户设置中的API key
    println!("🔑 正在获取用户设置...");
    let user_settings = get_user_settings();
    let api_key = user_settings.ai_settings.api_key.clone();

    if api_key.is_empty() {
        println!("❌ API Key 未配置");
        return Err("请先在设置中配置AI API Key".to_string());
    }
    
    println!("✅ API Key 已配置");

    // 将功能点分组，每组10个
    const GROUP_SIZE: usize = 10;
    let function_point_groups: Vec<Vec<String>> = function_points
        .chunks(GROUP_SIZE)
        .map(|chunk| chunk.to_vec())
        .collect();
    
    println!("📦 功能点分组完成: {} 个功能点分为 {} 组", function_points.len(), function_point_groups.len());
    
    // 存储所有分组的结果
    let mut all_table_data: Vec<Vec<String>> = Vec::new();
    
    // 使用 tokio::spawn 创建并发任务
    let mut tasks = Vec::new();
    
    for (group_index, group_points) in function_point_groups.into_iter().enumerate() {
        let requirement_name_clone = requirement_name.clone();
        let requirement_description_clone = requirement_description.clone();
        let selected_model_clone = selected_model.clone();
        let api_key_clone = api_key.clone();
        
        println!("🚀 启动第 {} 组处理任务，包含 {} 个功能点", group_index + 1, group_points.len());
        
        let task = tokio::spawn(async move {
            process_function_point_group(
                group_index + 1,
                group_points,
                requirement_name_clone,
                requirement_description_clone,
                data_movement_groups,
                selected_model_clone,
                api_key_clone,
            ).await
        });
        
        tasks.push(task);
    }
    
    // 等待所有任务完成并收集结果
    println!("⏳ 等待所有分组处理完成...");
    for (index, task) in tasks.into_iter().enumerate() {
        match task.await {
            Ok(Ok(group_data)) => {
                println!("✅ 第 {} 组处理完成，获得 {} 行数据", index + 1, group_data.len());
                all_table_data.extend(group_data);
            }
            Ok(Err(e)) => {
                println!("❌ 第 {} 组处理失败: {}", index + 1, e);
                return Err(format!("第 {} 组处理失败: {}", index + 1, e));
            }
            Err(e) => {
                println!("❌ 第 {} 组任务执行失败: {}", index + 1, e);
                return Err(format!("第 {} 组任务执行失败: {}", index + 1, e));
            }
        }
    }
    
    println!("🎯 所有分组处理完成！总共获得 {} 行数据", all_table_data.len());
    
    // 生成XLSX文件
    println!("📁 生成XLSX文件...");
    let file_path = generate_xlsx_file(&requirement_name, &all_table_data).await.map_err(|e| {
        println!("❌ 生成XLSX文件失败: {}", e);
        e
    })?;

    println!("🎉 COSMIC内容生成成功！文件路径: {}", file_path);
    Ok(GenerateCosmicResponse {
        file_path: Some(file_path),
        success: true,
        message: format!("COSMIC内容生成成功，共处理 {} 个功能点，生成 {} 行数据", function_points.len(), all_table_data.len()),
    })
}

// 解析Markdown表格
fn parse_markdown_table(content: &str) -> Result<Vec<Vec<String>>, String> {
    let lines: Vec<&str> = content.lines().collect();
    let mut table_data = Vec::new();
    
    for line in lines {
        let trimmed = line.trim();
        // 跳过表头分隔符行和空行
        if trimmed.is_empty() || trimmed.starts_with("|-") || trimmed.starts_with("|:") {
            continue;
        }
        
        // 处理表格行
        if trimmed.starts_with('|') && trimmed.ends_with('|') {
            let cells: Vec<String> = trimmed[1..trimmed.len()-1] // 去掉首尾的|
                .split('|')
                .map(|cell| cell.trim().to_string())
                .collect();
            
            // 跳过表头行（通常包含"功能用户需求"等字段名）和分隔行（包含---的行）
            if !cells.is_empty() && !cells[0].contains("功能用户需求") && !cells[0].contains("---") {
                table_data.push(cells);
            }
        }
    }
    
    if table_data.is_empty() {
        return Err("未能解析到有效的表格数据".to_string());
    }
    
    Ok(table_data)
}

// 生成XLSX文件
async fn generate_xlsx_file(requirement_name: &str, table_data: &[Vec<String>]) -> Result<String, String> {
    println!("📊 开始基于模板生成XLSX文件，需求名称: {}", requirement_name);
    println!("📋 表格数据行数: {}", table_data.len());
    
    // 生成输出文件路径
    println!("📁 生成输出文件路径...");
    let output_filename = format!("{}-cosmic工作量文档.xlsx", requirement_name);
    
    // 使用用户的下载目录，如果获取失败则使用文档目录，再失败则使用桌面
    let output_path = if let Some(download_dir) = dirs::download_dir() {
        download_dir.join(&output_filename)
    } else if let Some(document_dir) = dirs::document_dir() {
        document_dir.join(&output_filename)
    } else if let Some(desktop_dir) = dirs::desktop_dir() {
        desktop_dir.join(&output_filename)
    } else {
        // 最后的备选方案：使用当前用户的主目录
        dirs::home_dir()
            .unwrap_or_else(|| PathBuf::from("."))
            .join(&output_filename)
    };
    
    println!("📂 输出文件路径: {}", output_path.display());
    
    // 确保输出目录存在
    println!("📁 确保输出目录存在...");
    if let Some(parent) = output_path.parent() {
        fs::create_dir_all(parent).map_err(|e| {
            println!("❌ 创建输出目录失败: {}", e);
            format!("创建输出目录失败: {}", e)
        })?;
    }
    
    // 首先尝试使用嵌入的模板数据
    println!("📋 使用嵌入的模板数据创建文件...");
    match fs::write(&output_path, TEMPLATE_XLSX) {
        Ok(_) => {
            println!("✅ 成功使用嵌入的模板数据创建文件");
        },
        Err(e) => {
            println!("⚠️ 使用嵌入模板数据失败: {}, 尝试从文件系统复制", e);
            
            // 备用方案：从文件系统复制（开发环境）
            let template_path = {
                let dev_path = Path::new("src-tauri/template.xlsx");
                if dev_path.exists() {
                    dev_path.to_path_buf()
                } else {
                    let exe_dir = std::env::current_exe()
                        .map_err(|e| format!("无法获取可执行文件路径: {}", e))?
                        .parent()
                        .ok_or("无法获取可执行文件目录")?
                        .to_path_buf();
                    let resource_path = exe_dir.join("template.xlsx");
                    if resource_path.exists() {
                        resource_path
                    } else {
                        return Err("模板文件 template.xlsx 不存在，既不能使用嵌入数据，也不在文件系统中".to_string());
                    }
                }
            };
            
            fs::copy(&template_path, &output_path).map_err(|e| {
                println!("❌ 复制模板文件失败: {}", e);
                format!("复制模板文件失败: {}", e)
            })?;
            
            println!("✅ 从文件系统复制模板文件成功");
        }
    }
    
    // 使用umya-spreadsheet打开复制的文件
    println!("📝 使用umya-spreadsheet打开文件进行编辑...");
    let mut book = xlsx::read(&output_path).map_err(|e| {
        println!("❌ 打开Excel文件失败: {}", e);
        format!("打开Excel文件失败: {}", e)
    })?;
    
    // 获取工作表数量
    let worksheet_count = book.get_sheet_count();
    println!("📋 文件包含 {} 个工作表", worksheet_count);
    
    // 确保至少有3个工作表，如果没有第三个工作表则创建
    let target_sheet_index = 2; // 第三个工作表（索引从0开始，所以第三个是索引2）
    
    if worksheet_count <= target_sheet_index {
        println!("📝 创建缺失的工作表...");
        for i in worksheet_count..=target_sheet_index {
            let sheet_name = if i == 2 { "COSMIC数据移动" } else { &format!("Sheet{}", i + 1) };
            let _ = book.new_sheet(sheet_name);
            println!("📝 创建工作表: {} (索引: {})", sheet_name, i);
        }
    }
    
    // 获取第三个工作表
    let worksheet = if let Some(sheet) = book.get_sheet_by_name_mut("COSMIC数据移动") {
        sheet
    } else if let Some(sheet) = book.get_sheet_mut(&target_sheet_index) {
        sheet
    } else {
        println!("❌ 无法获取第三个工作表");
        return Err("无法获取第三个工作表".to_string());
    };
    
    println!("📄 成功获取第三个工作表");
    
    // 查找现有数据的最后一行
    println!("📊 查找现有数据的最后一行...");
    let mut last_row = 1u32; // 从第1行开始（Excel行号从1开始）
    
    // 检查前1000行，找到最后一个有数据的行
    for row in 1..=1000 {
        let mut has_data = false;
        for col in 1..=7 { // 检查前7列
            if let Some(cell) = worksheet.get_cell((col, row)) {
                if !cell.get_value().is_empty() {
                    has_data = true;
                    break;
                }
            }
        }
        if has_data {
            last_row = row + 1; // 下一行开始追加
        } else if last_row > 1 {
            // 如果当前行没有数据且已经找到过有数据的行，则停止搜索
            break;
        }
    }
    
    println!("📍 现有数据到第 {} 行，将从第 {} 行开始追加数据", last_row - 1, last_row);
    
    // 如果第一行是空的，先写入表头
    if last_row == 1 {
        println!("📝 写入表头...");
        let headers = vec![
            "功能用户需求", "参与者", "需求描述", "触发事件", 
            "功能过程", "子过程描述", "数据移动类型", "数据组", "数据属性"
        ];
        
        for (col_idx, header) in headers.iter().enumerate() {
            let col = (col_idx + 1) as u32; // Excel列从1开始
            worksheet.get_cell_mut((col, 1)).set_value(*header);
        }
        last_row = 2; // 下一行从第2行开始
        println!("✅ 表头写入成功");
    }
    
    // 追加COSMIC数据
    println!("📊 开始追加COSMIC数据，共 {} 行...", table_data.len());
    for (row_idx, row_data) in table_data.iter().enumerate() {
        let target_row = last_row + row_idx as u32;
        
        // 根据新的列结构写入数据
        if row_data.len() >= 7 {
            // 第1列：功能用户需求 (原第1列)
            worksheet.get_cell_mut((1, target_row)).set_value(&row_data[0]);
            
            // 第2列：参与者 (使用默认值)
            worksheet.get_cell_mut((2, target_row)).set_value("发起者：操作员，接收者：隐私计算门户");
            
            // 第3列：需求描述 (原第1列的内容，作为需求描述)
            worksheet.get_cell_mut((3, target_row)).set_value(&row_data[0]);
            
            // 第4列：触发事件 (原第2列)
            worksheet.get_cell_mut((4, target_row)).set_value(&row_data[1]);
            
            // 第5列：功能过程 (原第3列)
            worksheet.get_cell_mut((5, target_row)).set_value(&row_data[2]);
            
            // 第6列：子过程描述 (原第4列)
            worksheet.get_cell_mut((6, target_row)).set_value(&row_data[3]);
            
            // 第7列：数据移动类型 (原第5列)
            worksheet.get_cell_mut((7, target_row)).set_value(&row_data[4]);
            
            // 第8列：数据组 (原第6列)
            if row_data.len() > 5 {
                worksheet.get_cell_mut((8, target_row)).set_value(&row_data[5]);
            }
            
            // 第9列：数据属性 (原第7列)
            if row_data.len() > 6 {
                worksheet.get_cell_mut((9, target_row)).set_value(&row_data[6]);
            }
        }
        
        if (row_idx + 1) % 10 == 0 {
            println!("📊 已追加 {} 行COSMIC数据", row_idx + 1);
        }
    }
    
    println!("✅ COSMIC数据追加完成，共追加 {} 行", table_data.len());
    
    // 保存文件
    println!("💾 保存文件...");
    writer::write(&book, &output_path).map_err(|e| {
        println!("❌ 保存文件失败: {}", e);
        format!("保存文件失败: {}", e)
    })?;
    
    println!("🎉 文件保存成功: {}", output_path.display());
    
    // 使用reveal_item_in_dir显示生成的文件
    if let Err(e) = tauri_plugin_opener::reveal_item_in_dir(output_path.to_string_lossy().to_string()) {
        println!("⚠️ 无法打开文件夹: {}", e);
    } else {
        if let Some(parent_dir) = output_path.parent() {
            println!("📂 已打开文件夹: {}", parent_dir.display());
        }
    }
    
    Ok(output_path.to_string_lossy().to_string())
}

// 处理单个功能点分组的异步函数
async fn process_function_point_group(
    group_index: usize,
    group_points: Vec<String>,
    requirement_name: String,
    requirement_description: String,
    data_movement_groups: u32,
    selected_model: String,
    api_key: String,
) -> Result<Vec<Vec<String>>, String> {
    println!("🔄 第 {} 组开始处理，包含 {} 个功能点", group_index, group_points.len());
    
    // API配置
    let base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions";
    
    // 构建功能点列表字符串
    let function_points_str = group_points
        .iter()
        .enumerate()
        .map(|(i, point)| format!("{}. {}", i + 1, point))
        .collect::<Vec<String>>()
        .join("\n");
    
    println!("📝 第 {} 组功能点列表构建完成，长度: {}", group_index, function_points_str.len());

    // 构建prompt
    let prompt = format!(
r#"
我正在进行 COSMIC 功能点分析，请根据以下要求，严格为每个功能点生成 {} 组完整的数据移动序列。

基础信息：

需求名称：{}

需求描述：{}

输入：

功能点列表如下（每行为一个功能过程）：
{}

输出要求：

对每个功能点，必须输出 {} 组完整的数据移动操作，每组包含严格顺序的四个数据移动：E (Entry)、R (Read)、W (Write)、X (Exit)，顺序不可更改，不可省略。

每组必须严格包含以下字段：

功能用户需求：对应需求名称

触发事件：如"用户点击提交按钮"、"定时任务触发"等

功能过程：功能点

子过程描述：必须为详细的长文本描述（至少 20 个字），说明该步骤的目的、触发原因、涉及的数据内容以及与业务的关联，不能只写“接收输入/读取数据”这类简短描述；每个子过程描述应尽可能长且具体，突出业务逻辑和操作细节，且避免与同一功能点下的其他子过程描述雷同。

数据移动类型：E、R、W、X 四类之一

数据组：被访问的业务数据单元，如"用户信息表"、"订单记录"。每个功能点中的数据组应尽量避免重复，并且可以多组数据表以增加数据的细节层次，例如“用户信息表”、“订单记录”等。如果功能点涉及多个业务数据单元，可以在一行中多列出不同的数据组。注意数据组层次需要区分清楚。

数据属性：被使用的字段，如"用户ID"、"订单状态"。

每个功能点应输出共 {} × 4 行数据。

输出格式：

只输出严格 Markdown 表格，字段如下：

| 功能用户需求 | 触发事件 | 功能过程 | 子过程描述 | 数据移动类型 | 数据组 | 数据属性 |

⚠️ 注意：

不要输出任何解释性文字

不要输出表格以外的内容

每组数据必须是 E → R → W → X 顺序

每个功能点输出必须完整，不可缺行

"#,
        data_movement_groups,
        requirement_name,
        requirement_description,
        function_points_str,
        data_movement_groups,
        data_movement_groups
    );

    // 构建请求体
    let request_body = json!({
        "model": selected_model,
        "messages": [
            {
                "role": "user",
                "content": prompt
            }
        ],
        "temperature": 0.7,
        "max_tokens": 8000
    });

    // 发送HTTP请求
    println!("🌐 第 {} 组发送HTTP请求到AI API...", group_index);
    let client = reqwest::Client::new();
    let response = client
        .post(base_url)
        .header("Authorization", format!("Bearer {}", api_key))
        .header("Content-Type", "application/json")
        .json(&request_body)
        .send()
        .await
        .map_err(|e| {
            println!("❌ 第 {} 组HTTP请求失败: {}", group_index, e);
            format!("第 {} 组请求失败: {}", group_index, e)
        })?;

    println!("📡 第 {} 组收到HTTP响应，状态码: {}", group_index, response.status());
    if !response.status().is_success() {
        println!("❌ 第 {} 组API请求失败，状态码: {}", group_index, response.status());
        return Err(format!("第 {} 组API请求失败，状态码: {}", group_index, response.status()));
    }

    println!("📄 第 {} 组解析响应JSON...", group_index);
    let response_json: serde_json::Value = response
        .json()
        .await
        .map_err(|e| {
            println!("❌ 第 {} 组解析响应JSON失败: {}", group_index, e);
            format!("第 {} 组解析响应失败: {}", group_index, e)
        })?;

    // 提取AI回复内容
    println!("🤖 第 {} 组提取AI回复内容...", group_index);
    let content = response_json["choices"][0]["message"]["content"]
        .as_str()
        .ok_or_else(|| {
            println!("❌ 第 {} 组无法获取AI回复内容", group_index);
            format!("第 {} 组无法获取AI回复内容", group_index)
        })?;
    
    println!("✅ 第 {} 组AI回复内容长度: {}", group_index, content.len());
    let preview = content.chars().take(50).collect::<String>();
    println!("📝 第 {} 组AI回复内容预览: {}", group_index, preview);

    // 解析Markdown表格
    println!("📊 第 {} 组解析Markdown表格...", group_index);
    let table_data = parse_markdown_table(content).map_err(|e| {
        println!("❌ 第 {} 组解析Markdown表格失败: {}", group_index, e);
        format!("第 {} 组解析表格失败: {}", group_index, e)
    })?;
    
    println!("✅ 第 {} 组表格解析成功，行数: {}", group_index, table_data.len());
    
    Ok(table_data)
}